#include <math.h>

inline static void swapCols(double A[], int N, int col1, int col2)
{
    for (int row = 0; row <= N-1; row++)
    {
        int p = row * N + col1;
        int q = row * N + col2;
        double t = A[p];
        A[p] = A[q];
        A[q] = t;
    }
}

inline static void swap(double &a, double &b)
{
    double t = a;
    a = b;
    b = t;
}


/**
 * @brief cagaus 全选主元高斯消去法求解线性代数方程组 Ax = b
 * @note 这个代码改编自徐世良编著的《C常用算法程序集》
 * @param A[] 线性代数方程组的系数矩阵，要求系数矩阵是 n * n 方阵，行优先存储。
 * @param b[] n 个元素的数组。
 * @param perm[] 辅助数组，n 个元素。函数利用这个数组来记录选主元过程中的位置交换。
 * @param n 线性代数方程组的阶数。
 * @param x[] 计算的结果。
 * @return true 表示计算成功，false 则表明系数矩阵奇异
 */
bool cagaus(double A[],double b[], int perm[], int N, double x[])
{    
    for (int row = 0; row <= N - 2; row++) //依次找每一行的主元，这个主元不一定在当前行。
    {
        double pivot = 0.0; //主元
        int pivot_row; //主元所在的行
        for (int i = row; i <= N - 1; i++) //全选主元，即选择矩阵中最大的一个，转化为找最大值问题
        {
            for (int j = row; j <= N - 1; j++)
            {
                double t = fabs(A[i * N + j]); //当然是绝对值最大一个，这里用到了数学库绝对值函数fabs()
                if (t > pivot)
                {
                    pivot = t;
                    perm[row] = j; //第 row 行的主元所在的列
                    pivot_row = i; //主元所在的行
                }
            }
        }
        if (pivot + 1.0 == 1.0)
        {
            return false; //主元为 0， 说明是奇异矩阵
        }
        else
        {
            if (perm[row] != row) //主元不在当前列，所以要进行列交换
            {
                swapCols(A, N, row, perm[row]);
            }
            if (pivot_row != row) //主元不在当前行，所以要进行行交换
            {
                for (int j = row; j <= N-1; j++)
                {
                    int p = row * N + j;
                    int q = pivot_row * N + j;
                    swap(A[p], A[q]);
                }
                swap(b[row], b[pivot_row]);
            }
        }

        pivot = A[row * N + row]; //归一化 start
        for (int j = row + 1; j <= N-1; j++)
        {
            int p = row * N + j;
            A[p] = A[p] / pivot;
        }
        b[row] = b[row] / pivot; //归一化 end

        for (int i = row + 1; i <= N - 1; i++) //消元
        {
            for (int j = row + 1; j <= N - 1; j++)
            {
                int p = i * N + j;
                A[p] = A[p] - A[i * N + row] * A[row * N + j];
            }
            b[i] = b[i] - A[i * N + row] * b[row];
        }
    }
    double d = A[(N-1) * N + N - 1]; // 最后一行的主元
    if (d + 1.0 == 1.0)
    {
        return false; // 如果这个主元是 0，说明是奇异矩阵
    }
    x[N - 1] = b[N - 1] / d; //计算解向量的最后一个分量
    for (int i = N - 2; i >= 0; i--) //回代过程
    {
        double t = 0.0;
        for (int j = i + 1; j <= N - 1; j++)
        {
            t = t + A[i * N + j] * x[j];
        }
        x[i] = b[i] - t;
    }
    perm[N - 1] = N - 1;
    for (int k = N - 1; k >= 0; k--) //恢复解向量，交换位置的地方再交换回来
    {
        if (perm[k] != k)
        {
            swap(x[k], x[perm[k]]);
        }
    }
    return true;
}
